package com.brillilab.service.logic.method;

import com.brillilab.common.alioss.OssFileEnum;
import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.entity.PageVo;
import com.brillilab.common.exceptions.BrillilabException;
import com.brillilab.domain.crm.kitRelateMethod.po.PublicMethodRelateReagent;
import com.brillilab.domain.enums.common.BoolEnum;
import com.brillilab.domain.enums.method.*;
import com.brillilab.domain.po.global.GlobalKit;
import com.brillilab.domain.po.kit.Kit;
import com.brillilab.domain.po.method.*;
import com.brillilab.domain.po.system.FileManage;
import com.brillilab.domain.po.user.Users;
import com.brillilab.domain.vo.method.*;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.core.crm.IPublicMethodRelateReagentService;
import com.brillilab.service.core.global.IGlobalKitService;
import com.brillilab.service.core.kit.IKitService;
import com.brillilab.service.core.lab.ILabService;
import com.brillilab.service.core.method.*;
import com.brillilab.service.core.system.IFileManageService;
import com.brillilab.service.core.user.IUsersService;
import com.brillilab.service.logic.kit.GlobalKitLogic;
import com.google.common.base.Joiner;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author wuzhiyu
 * @Title: MethodLogic
 * @ProjectName brill_lab
 * @Description: TODO
 * @date 2019/2/2113:13
 */
@Service
@Transactional
public class MethodLogic {
    @Resource
    private IMethodService methodService;
    @Resource
    private IMethodPhaseService methodPhaseService;
    @Resource
    private IMethodTypeService methodTypeService;
    @Resource
    private IMethodStepService methodStepService;
    @Resource
    private IMethodLabViewService methodLabViewService;
    @Resource
    private IMethodTypeUseService methodTypeUseService;
    @Resource
    private IMethodShareService methodShareService;
    @Resource
    private IMethodRecommendAuditService methodRecommendAuditService;
    @Resource
    private IMethodRelateReagentService methodRelateReagentService;
    @Resource
    private MethodTypeLogic methodTypeLogic;
    @Resource
    private ILabService labService;
    @Resource
    private IUsersService usersService;
    @Resource
    private IMethodRelateTimerService methodRelateTimerService;
    @Resource
    private IFileManageService fileManageService;
    @Resource
    private IPublicMethodRelateReagentService publicMethodRelateReagentService;
    @Resource
    private IGlobalKitService globalKitService;
    @Resource
    private MethodRecommendLogic methodRecommendLogic;
    @Resource
    private GlobalKitLogic globalKitLogic;
    @Resource
    private IKitService kitService;

    /**
     * @return boolean
     * @Description: 新增方法  导入/手工
     * @Params: [newMethod, user]
     * @author wuzhiyu
     * @date 2019/2/26 17:17
     */
    public Long addNewMethod(NewMethod newMethod, UserInfoVo user) {
        if (newMethod.getFromType() == null) {
            throw new BrillilabException(ResultEnum.DATA_NOT_EXIST);
        }
        MethodType methodType = methodTypeService.getMethodTypeById(newMethod.getMethodTypeId());
        //Assert.isTrue(methodType != null && (methodType.getUserId() == null || user.getId().equals(methodType.getUserId())), "类型不存在");
        MethodType myThird = findMyThirdTypeOrCreateNew(user.getId(), methodType.getId(), true, true);
        Method method = new Method();
        BeanUtils.copyProperties(newMethod, method);
        method.setMethodTypeId(myThird.getId());
        if (MethodSourceEnum.CREATE.getSourceType().equals(method.getFromType())) {
            method.setFromTime(new Date());
        }
        setVersionUserIdCurrentDeleteAndSave(newMethod, user, method, 0, true);
        methodAttachFileDeal(newMethod.getUploadFileIdList(), newMethod.getCopyFileIdList(), user, method.getId());
        methodLabViewAndTypeUsage(user, myThird, method);
        return method.getId();
    }


    /**
     * @return com.brillilab.domain.vo.method.MethodDetail
     * @Description: 获取方法详情
     * @Params: [id, user]
     * @author wuzhiyu
     * @date 2019/2/26 17:18
     */
    public MethodDetail getMethodDetail(Long id, BoolEnum isDelete, Long labId) {
        Method method = methodService.getById(id);
        Assert.isTrue(method != null, "方法不存在");
        MethodDetail methodDetail = new MethodDetail();
        BeanUtils.copyProperties(method, methodDetail);
        MethodTypeDetailVo typelVo = methodTypeService.getMethodFullNameByThirdId(method.getMethodTypeId());
        methodDetail.setFirstTypeId(typelVo.getFirstTypeId());
        methodDetail.setFirstTypeName(typelVo.getFirstTypeName());
        methodDetail.setSecondTypeId(typelVo.getSecondTypeId());
        methodDetail.setSecondTypeName(typelVo.getSecondTypeName());
        methodDetail.setMethodTypeName(typelVo.getFullName());
        methodDetail.setThirdTypeName(typelVo.getMethodTypeName());

        List<Long> idList = new ArrayList<>();
        if (method.getRecommendMethodId() != null) {
            idList.add(method.getRecommendMethodId());
        }
        List<MethodRecommendAudit> auditList = methodRecommendAuditService.getIsRecommendMethodAuditList(idList);
        methodDetail.setIsRecommend(method.getRecommendMethodId() == null ? BoolEnum.FALSE.getValue() : (auditList.stream().filter(o -> o.getRecommendMethodId() != null && o.getLabId().equals(labId)).anyMatch(x -> x.getRecommendMethodId().equals(method.getRecommendMethodId()))) ? BoolEnum.TRUE.getValue() : BoolEnum.FALSE.getValue());
        MethodRecommendAudit rAudit = methodRecommendAuditService.getRecommendAuditByMethodId(id, labId);
        methodDetail.setIsSubmitAudit(rAudit != null ? BoolEnum.TRUE.getValue() : BoolEnum.FALSE.getValue());
        List<MethodPhase> phaseList = methodPhaseService.listByMethodId(id, isDelete);
        List<MethodStep> stepList = methodStepService.listByMethodId(id, isDelete);
        List<MethodRelateReagent> relateReagentList = new ArrayList<>();
        List<MethodRelateTimer> timerList = new ArrayList<>();
        if (method.getUserId() != null) {
            List<MethodRelateReagent> dbRelateReagentList = methodRelateReagentService.listMethodRelateReagentByMethodId(id);
            relateReagentList.addAll(dbRelateReagentList);
            List<MethodRelateTimer> dbTimerList = methodRelateTimerService.getByMethodId(id);
            timerList.addAll(dbTimerList);
        } else {
            List<PublicMethodRelateReagent> publicMethodRelateReagentList = publicMethodRelateReagentService.getPublicMethodRelateReagentListByMethodId(method.getId());
            publicMethodRelateReagentList.forEach(r -> {
                MethodRelateReagent newRelate = new MethodRelateReagent();
                newRelate.setMethodId(r.getMethodId());
                newRelate.setPhaseId(r.getPhaseId());
                newRelate.setStepId(r.getStepId());
                newRelate.setUuid(r.getUuid());
                newRelate.setReagentName(r.getReagentName());
                newRelate.setGlobalReagentId(r.getGlobalReagentId());
                newRelate.setType(2);
                relateReagentList.add(newRelate);
            });
        }
        List<MethodPhaseDetail> phaseDetailList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(phaseList)) {
            phaseList.forEach(p -> {
                MethodPhaseDetail mpd = new MethodPhaseDetail();
                BeanUtils.copyProperties(p, mpd);
                phaseDetailList.add(mpd);
                List<MethodStepDetail> stepDetailList = new ArrayList<>();
                if (!CollectionUtils.isEmpty(stepList)) {
                    List<MethodStep> pStepList = stepList.stream().filter(st -> p.getId().equals(st.getMethodPhaseId())).collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(pStepList)) {
                        pStepList.forEach(ps -> {
                            MethodStepDetail nsd = new MethodStepDetail();
                            BeanUtils.copyProperties(ps, nsd);
                            nsd.setReagentList(new ArrayList<>());
                            nsd.setTimerList(new ArrayList<>());
                            if (!CollectionUtils.isEmpty(relateReagentList)) {
                                List<MethodRelateReagentVo> kitVoList = relateReagentList.stream().filter(r -> r.getStepId().equals(ps.getId())&&r.getType().equals(1)).map(r -> new MethodRelateReagentVo(null, r.getUuid(), null, null, null, r.getKitId(), r.getKitName(), r.getType(), null)).filter(distinctByKey(MethodRelateReagentVo::getUuid)).collect(Collectors.toList());
                                List<MethodRelateReagentVo> reagentVoList = relateReagentList.stream().filter(r -> r.getType().equals(2)).map(r -> new MethodRelateReagentVo(null, r.getUuid(), r.getGlobalReagentId(), r.getReagentId(), r.getReagentName(), null, null, r.getType(), null)).collect(Collectors.toList());
                                nsd.getReagentList().addAll(kitVoList);
                                nsd.getReagentList().addAll(reagentVoList);
                            }
                            if (!CollectionUtils.isEmpty(timerList)) {
                                List<MethodRelateTimer> stepTimerList = timerList.stream().filter(t -> t.getStepId().equals(ps.getId())).collect(Collectors.toList());
                                nsd.getTimerList().addAll(stepTimerList);
                            }
                            stepDetailList.add(nsd);
                        });
                    }
                }
                stepDetailList.sort((x, y) -> {
                    if (x.getSort() != null && y.getSort() != null) {
                        return x.getSort() - y.getSort();
                    }
                    return -1;
                });
                mpd.setStepList(stepDetailList);
            });
        }
        methodDetail.setPhaseList(phaseDetailList);
        OssFileEnum attachType;
        if (method.getUserId() != null) {
            attachType = OssFileEnum.Method;
        } else {
            attachType = OssFileEnum.PublicMethod;
        }
        List<FileManage> fileList = fileManageService.selectList(attachType, method.getId());
        methodDetail.setUploadFileList(fileList);
        return methodDetail;
    }
    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }
    /**
     * @return java.util.List<com.brillilab.domain.vo.method.ReferMethodListItem>
     * @Description: 获取参考方法列表
     * @Params: [thirdTypeId, searchName]
     * @author wuzhiyu
     * @date 2019/2/26 17:19
     */
    public PageVo<ReferMethodListItem> getReferList(Long secondTypeId, String searchName, Integer pageIndex, Integer rows, boolean isKit) {
        List<Long> thirdTypeIdList = new ArrayList<>();
        if (secondTypeId != null) {
            List<MethodType> thirdTypeList = methodTypeService.selectThirdListBySecondId(secondTypeId, null);
            thirdTypeIdList = thirdTypeList.stream().map(MethodType::getId).distinct().collect(Collectors.toList());
        }
        PageVo<ReferMethodListItem> resultPage = new PageVo<>();
        if (secondTypeId != null && CollectionUtils.isEmpty(thirdTypeIdList)) {
            return resultPage;
        }
        PageVo<Method> page = methodService.listPagedReferMethod(thirdTypeIdList, searchName, pageIndex, rows, isKit);
        List<Method> methodList = page.getContent();
        List<MethodType> typeList = methodTypeService.listPublicMethodType();
        BeanUtils.copyProperties(page, resultPage);
        List<ReferMethodListItem> result = new ArrayList<>();
        resultPage.setContent(result);
        if (!CollectionUtils.isEmpty(methodList)) {
            methodList.forEach(m -> {
                ReferMethodListItem item = new ReferMethodListItem();
                item.setName(m.getName());
                item.setId(m.getId());
                item.setExportCount(m.getExportCount());
                item.setAuthor(m.getAuthor());
                item.setTypeId(m.getMethodTypeId());
                MethodType third = typeList.stream().filter(t -> t.getId().equals(m.getMethodTypeId()) && t.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel())).findFirst().get();
                MethodType second = typeList.stream().filter(t -> t.getId().equals(third.getSecondId()) && t.getLevel().equals(MethodTypeLevelEnum.LevelSecond.getLevel())).findFirst().get();
                MethodType first = typeList.stream().filter(t -> t.getId().equals(third.getFirstId()) && t.getLevel().equals(MethodTypeLevelEnum.LevelFirst.getLevel())).findFirst().get();
                item.setTypeName(first.getName() + "->" + second.getName() + "->" + third.getName());
                item.setFirstTypeId(first.getId());
                result.add(item);
            });
        }
        return resultPage;
    }

    /**
     * @return boolean
     * @Description: 判断方法是否存在 0直接保存1保存新版本2修改方法名
     * @Params: [typeName, methodName, user]
     * @author wuzhiyu
     * @date 2019/2/26 17:19
     */
    public MethodExistVo sameMethodExist(Long otherMethodId, UserInfoVo user) {
        Method method = methodService.getById(otherMethodId);
        Assert.notNull(method, "数据不存在");
        List<MethodType> otherThreeType = methodTypeService.listThreeLevelTypeByThirdId(method.getMethodTypeId());
        Optional<MethodType> otherThirdTypeOpt = otherThreeType.stream().filter(t -> t.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel())).findFirst();
        Assert.isTrue(otherThirdTypeOpt.isPresent(), "数据不存在");
        MethodExistVo existVo = new MethodExistVo();
        existVo.setExist(SameMethodExistEnum.TYPE_NOT_SAME.getCode());
        List<Method> methodList = methodService.getMethodListByUserIdAndState(user.getId(), BoolEnum.FALSE, BoolEnum.TRUE,false);
        List<MethodType> allTypeList = methodTypeService.listUserAllType(user.getId());
        List<MethodType> sameNameList = allTypeList.stream().filter(a -> a.getName().equals(otherThirdTypeOpt.get().getName()) && MethodTypeLevelEnum.LevelThird.getLevel().equals(a.getLevel())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(sameNameList)) {
            existVo.setExist(SameMethodExistEnum.TYPE_NOT_SAME.getCode());
            return existVo;
        }
        Map<Long, String> typeNameCache = allTypeList.stream().filter(t -> t.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel())).collect(Collectors.toMap(MethodType::getId, t -> {
            return Joiner.on("-").join(allTypeList.stream().filter(f -> f.getId().equals(t.getFirstId())).findFirst().get().getName(), allTypeList.stream().filter(s -> s.getId().equals(t.getSecondId())).findFirst().get().getName(), t.getName());
        }));
        String otherSec = otherThreeType.stream().filter(o -> o.getLevel().equals(MethodTypeLevelEnum.LevelSecond.getLevel())).findFirst().get().getName();
        String otherFirst = otherThreeType.stream().filter(o -> o.getLevel().equals(MethodTypeLevelEnum.LevelFirst.getLevel())).findFirst().get().getName();
        String otherTypeFullName = Joiner.on("-").join(otherFirst, otherSec, otherThirdTypeOpt.get().getName());
        if (typeNameCache.containsValue(otherTypeFullName)) {
            List<Long> sameTypeIdList = new ArrayList<>();
            for (Map.Entry<Long, String> set : typeNameCache.entrySet()) {
                if (set.getValue().equals(otherTypeFullName)) {
                    sameTypeIdList.add(set.getKey());
                }
            }
            List<Method> sameTypeMethodList = methodList.stream().filter(m -> sameTypeIdList.contains(m.getMethodTypeId())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(sameTypeMethodList)) {
                if (method.getSourceMethodId() != null) {
                    Optional<Method> sourceOpt = sameTypeMethodList.stream().filter(m -> m.getSourceMethodId() != null && m.getSourceMethodId().equals(method.getSourceMethodId()) && sameTypeIdList.contains(m.getMethodTypeId())).findFirst();
                    if (sourceOpt.isPresent()) {
                        existVo.setExist(SameMethodExistEnum.TYPE_SAME_SOURCE_SAME.getCode());
                        existVo.setMyExistInitMethodId(sourceOpt.get().getInitMethodId());
                    } else {
                        List<Method> sameNameTypeList = sameTypeMethodList.stream().filter(m -> m.getName().equals(method.getName())).collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(sameNameTypeList)) {
                            existVo.setExist(SameMethodExistEnum.TYPE_SAME_NAME_SAME_SOURCE_NOT_SAME.getCode());
                        } else {
                            existVo.setExist(SameMethodExistEnum.TYPE_SAME_SOURCE_NOT_SAME_NAME_NOT_SAME.getCode());
                        }
                    }
                } else {
                    List<Method> sameNameTypeList = sameTypeMethodList.stream().filter(m -> m.getName().equals(method.getName())).collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(sameNameTypeList)) {
                        existVo.setExist(SameMethodExistEnum.TYPE_SAME_NAME_SAME_SOURCE_NOT_SAME.getCode());
                    } else {
                        existVo.setExist(SameMethodExistEnum.TYPE_SAME_SOURCE_NOT_SAME_NAME_NOT_SAME.getCode());
                    }
                }
            } else {
                existVo.setExist(SameMethodExistEnum.TYPE_SAME_NO_METHOD.getCode());
            }
        } else {
            existVo.setExist(SameMethodExistEnum.TYPE_NOT_SAME.getCode());
        }
        return existVo;
    }

    /**
     * @return java.util.List<com.brillilab.domain.vo.method.MethodListItem>
     * @Description: 同类型方法（对比时选择用）
     * @Params: [thirdType, user]
     * @author wuzhiyu
     * @date 2019/2/26 17:19
     */
    public List<MethodListItem> methodListByTypeId(Long thirdType, UserInfoVo user) {
        MethodType methodType = methodTypeService.getMethodTypeById(thirdType);
        if (methodType == null || !methodType.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel())) {
            throw new BrillilabException(ResultEnum.DATA_NOT_EXIST);
        }
        MethodType sharedSecondType = methodTypeService.selectOneById(methodType.getSecondId());
        if (sharedSecondType == null || !sharedSecondType.getLevel().equals(MethodTypeLevelEnum.LevelSecond.getLevel())) {
            throw new BrillilabException(ResultEnum.DATA_NOT_EXIST);
        }
        MethodType mySecondType = methodTypeService.selectSecondType(sharedSecondType.getName(), sharedSecondType.getFirstId(), user.getId());
        if (mySecondType == null || !mySecondType.getLevel().equals(MethodTypeLevelEnum.LevelSecond.getLevel())) {
            return new ArrayList<>();
        }
        MethodType myThirdType = methodTypeService.selectThirdType(methodType.getName(), mySecondType.getId(), user.getId());
        if (myThirdType == null || !myThirdType.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel())) {
            return new ArrayList<>();
        }
        List<Method> methodList = methodService.listByTypeIdAndUserId(myThirdType.getId(), user.getId());
        List<MethodListItem> result = new ArrayList<>();
        if (!CollectionUtils.isEmpty(methodList)) {
            methodList.forEach(m -> {
                MethodListItem item = new MethodListItem();
                item.setExportCount(m.getExportCount());
                item.setName(m.getName());
                item.setId(m.getId());
                item.setSuccessCount(m.getSuccessCount());
                item.setSourceMethodId(m.getSourceMethodId());
                item.setFirstTypeId(myThirdType.getFirstId());
                item.setSuccessRate(m.getExportCount().equals(0) ? BigDecimal.ZERO : BigDecimal.valueOf(m.getSuccessCount()).divide(BigDecimal.valueOf(m.getExportCount()), 4, RoundingMode.HALF_UP));
                item.setIsRecommend(false);
                if (m.getRecommendMethodId() != null) {
                    MethodRecommendAudit audit = methodRecommendAuditService.getByRecommendMethodId(user.getLabId(), m.getRecommendMethodId());
                    item.setIsRecommend(audit != null && audit.getState().equals(RecommendAuditStateEnum.Recommend.getState()));
                }
                if (m.getFromType().equals(MethodSourceEnum.CREATE.getSourceType())) {
                    item.setSourceName(MethodSourceEnum.CREATE.getName());
                } else if (m.getFromType().equals(MethodSourceEnum.RECOMMEND.getSourceType())) {
                    item.setSourceName(MethodSourceEnum.RECOMMEND.getName());
                } else if (m.getFromType().equals(MethodSourceEnum.SHARE.getSourceType())) {
                    item.setSourceName(MethodSourceEnum.SHARE.getName());
                } else {
                    item.setSourceName(MethodSourceEnum.IMPORT.getName());
                }
                result.add(item);
            });
        }
        return result;
    }

    /**
     * @return boolean
     * @Description: 设为最新版方法
     * @Params: [methodIdList, user]
     * @author wuzhiyu
     * @date 2019/2/26 17:20
     */
    public Long resetToCurrent(Long methodId, UserInfoVo user) {
        Method method = methodService.getById(methodId);
        Assert.notNull(method, "数据不存在 ");
        Assert.isTrue(method.getUserId().equals(user.getId()), "数据不存在");
        List<MethodPhase> phaseList = methodPhaseService.listByMethodId(methodId, null);
        List<MethodStep> stepList = methodStepService.listByMethodId(method.getId(), null);
        List<MethodRelateReagent> otherRelateReagentList = methodRelateReagentService.listMethodRelateReagentByMethodId(method.getId());
        MethodType thirdType = methodTypeService.getMethodTypeById(method.getMethodTypeId());
        List<MethodRelateTimer> sourceRelateTimerList = methodRelateTimerService.getByMethodId(method.getId());
        MethodFullInfo existInfo = composeMethodFullInfo(method, phaseList, stepList, null, null);
        MethodFullInfo sourceInfo = composeMethodFullInfo(method, phaseList, stepList, otherRelateReagentList, sourceRelateTimerList);
        MethodSaveDto saveDto = new MethodSaveDto(existInfo, sourceInfo, MethodSourceEnum.REST_CURRENT, null, null, false, null, thirdType, user, methodService.getCurrentMaxVersion(method.getInitMethodId()) + 1);
        Method newVersionMethod = copyToMyMethod(saveDto);
        //fixme 附件处理
        List<FileManage> fileList = fileManageService.selectList(OssFileEnum.Method, method.getId());
        if (!CollectionUtils.isEmpty(fileList)) {
            List<FileManage> copies = new ArrayList<>();
            fileList.forEach(fileManage -> {
                fileManage.setId(null);
                fileManage.setReferDataId(newVersionMethod.getId());
                fileManage.setUserId(user.getId());
                fileManage.setLabId(null);
                fileManage.setCreateTime(null);
                copies.add(fileManage);
            });
            fileManageService.insertBatch(copies);
        }
        return newVersionMethod.getId();
    }

    /**
     * @return boolean
     * @Description: 新增新版本
     * @Params: [newMethod, user]
     * @author wuzhiyu
     * @date 2019/2/26 17:20
     */
    public Long addNewVersion(NewMethod newMethod, UserInfoVo user) {
        MethodLabView view = methodLabViewService.getByInitMethodId(newMethod.getInitMethodId());
        Method myMethod = new Method();
        Integer maxVersion = methodService.getCurrentMaxVersion(newMethod.getInitMethodId());
        BeanUtils.copyProperties(newMethod, myMethod);
        Integer currentV = maxVersion == null ? 0 : maxVersion + 1;
        myMethod.setRecommendMethodId(null);
        setVersionUserIdCurrentDeleteAndSave(newMethod, user, myMethod, currentV, false);
        MethodLabView newView = new MethodLabView();
        newView.setId(view.getId());
        newView.setCurrentMethodId(myMethod.getId());
        methodLabViewService.updateById(newView);
        methodAttachFileDeal(newMethod.getUploadFileIdList(), newMethod.getCopyFileIdList(), user, myMethod.getId());
        return myMethod.getId();
    }


    /**
     * @return java.util.List<com.brillilab.domain.vo.method.MethodVersionListItem>
     * @Description: 获取版本历史
     * @Params: [methodIdList, user]
     * @author wuzhiyu
     * @date 2019/2/26 17:21
     */
    public List<MethodVersionListItem> listVersionList(Long methodId, UserInfoVo user) {
        Method method = methodService.getById(methodId);
        if (method == null) {
            throw new BrillilabException(ResultEnum.DATA_NOT_EXIST);
        }
        List<Method> list = methodService.listByInitMethodId(method.getInitMethodId(), user.getId());
        List<MethodVersionListItem> versionList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(list)) {
            List<Long> allRecommendIdMethodList = list.stream().filter(m -> m.getRecommendMethodId() != null).map(Method::getRecommendMethodId).distinct().collect(Collectors.toList());
            List<MethodRecommendAudit> isRecommendAuditList = methodRecommendAuditService.getIsRecommendMethodAuditList(allRecommendIdMethodList);
            list.forEach(l -> {
                MethodVersionListItem item = new MethodVersionListItem();
                item.setCreateTime(l.getCreateTime());
                item.setExportCount(l.getExportCount());
                item.setMethodId(l.getId());
                item.setSourceMethodId(l.getSourceMethodId());
                item.setSuccessCount(l.getSuccessCount());
                item.setVersion(l.getVersion());
                item.setIsRecommend(l.getRecommendMethodId() == null ? false : isRecommendAuditList.stream().anyMatch(a -> l.getRecommendMethodId().equals(a.getRecommendMethodId())));
                if (l.getFromType().equals(MethodSourceEnum.CREATE.getSourceType())) {
                    item.setFromStr(MethodSourceEnum.CREATE.getName());
                } else if (l.getFromType().equals(MethodSourceEnum.RECOMMEND.getSourceType())) {
                    item.setFromStr(MethodSourceEnum.RECOMMEND.getName());
                } else if (l.getFromType().equals(MethodSourceEnum.SHARE.getSourceType())) {
                    item.setFromStr(MethodSourceEnum.SHARE.getName());
                } else {
                    item.setFromStr(MethodSourceEnum.IMPORT.getName());
                }
                item.setFromType(l.getFromType());
                item.setMethodTypeId(l.getMethodTypeId());
                versionList.add(item);
            });
        }
        return versionList;
    }

    public MethodSameSourceDiffVo versionDiff(Long methodIId, boolean isPrevious, UserInfoVo user) {
        Method currentMethod = methodService.getById(methodIId);
        Assert.notNull(currentMethod, "方法不存在");
        Assert.isTrue(user.getId().equals(currentMethod.getUserId()), "方法不存在");
        Integer version = 0;
        if (isPrevious) {
            version = currentMethod.getVersion() - 1;
        } else {
            version = methodService.getCurrentMaxVersion(currentMethod.getInitMethodId());
        }
        Method diffMethod = methodService.getByInitMethodIdAndVersion(currentMethod.getInitMethodId(), version);
        Assert.notNull(diffMethod, "方法不存在");
        return sameSourceMethodDiff(isPrevious, user, currentMethod, diffMethod);
    }

    private MethodSameSourceDiffVo sameSourceMethodDiff(boolean isPrevious, UserInfoVo user, Method currentMethod, Method diffMethod) {
        List<MethodPhase> currentPhaseList = methodPhaseService.listByMethodId(currentMethod.getId(), null);
        List<MethodPhase> diffPhaseList = methodPhaseService.listByMethodId(diffMethod.getId(), null);
        List<MethodStep> currentStepList = methodStepService.listByMethodId(currentMethod.getId(), null);
        List<MethodStep> diffStepList = methodStepService.listByMethodId(diffMethod.getId(), null);
        MethodSameSourceDiffVo methodDiff = new MethodSameSourceDiffVo();
        methodDiff.setName(currentMethod.getName());
        methodDiff.setOtherName(diffMethod.getName());
        methodDiff.setAuthor(currentMethod.getAuthor());
        methodDiff.setLink(currentMethod.getLink());
        methodDiff.setExportCount(currentMethod.getExportCount());
        methodDiff.setFromTime(currentMethod.getFromTime());
        methodDiff.setImportTime(currentMethod.getImportTime());
        methodDiff.setSourceName(currentMethod.getSourceName());
        methodDiff.setSuccessCount(currentMethod.getSuccessCount());
        DiffVo desc = new DiffVo();
        if (!StringUtils.isEmpty(currentMethod.getDescription()) && !currentMethod.getDescription().equals(diffMethod.getDescription())) {
            desc.setCurrent(currentMethod.getDescription());
            desc.setOther(diffMethod.getDescription());
            desc.setDiffType(MethodDiffEnum.Edit.getType());
        } else if (!StringUtils.isEmpty(diffMethod.getDescription()) && !diffMethod.getDescription().equals(currentMethod.getDescription())) {
            desc.setCurrent(currentMethod.getDescription());
            desc.setOther(diffMethod.getDescription());
            desc.setDiffType(MethodDiffEnum.Edit.getType());
        } else {
            desc.setCurrent(currentMethod.getDescription());
            desc.setDiffType(MethodDiffEnum.Equal.getType());
        }
        methodDiff.setDescription(desc);
        methodDiff.setUpdateTime(currentMethod.getUpdateTime());
        MethodType methodType = methodTypeService.getMethodTypeById(currentMethod.getMethodTypeId());
        methodDiff.setFromType(currentMethod.getFromType());
        List<FileManage> fileList = fileManageService.selectList(OssFileEnum.Method, currentMethod.getId());
        methodDiff.setUploadFileList(fileList);
        String firstMethodTypeName = methodTypeService.selectOneById(methodType.getFirstId()).getName();
        String secondMethodTypeName = methodTypeService.selectOneById(methodType.getSecondId()).getName();
        methodDiff.setMethodType(firstMethodTypeName + "-" + secondMethodTypeName + "-" + methodType.getName());
        DiffVo descDiff = new DiffVo();
        descDiff.setCurrent(currentMethod.getDescription());
        if ((!StringUtils.isEmpty(currentMethod.getDescription()) && !StringUtils.isEmpty(diffMethod.getDescription())) && (!currentMethod.getDescription().equals(diffMethod.getDescription()))) {
            descDiff.setOther(diffMethod.getDescription());
            descDiff.setDiffType(MethodDiffEnum.Edit.getType());
        } else if ((StringUtils.isEmpty(currentMethod.getDescription()) && !StringUtils.isEmpty(diffMethod.getDescription())) || (StringUtils.isEmpty(diffMethod.getDescription()) && !StringUtils.isEmpty(currentMethod.getDescription()))) {
            descDiff.setOther(diffMethod.getDescription());
            descDiff.setDiffType(MethodDiffEnum.Edit.getType());
        }
        List<MethodPhaseDiffVo> phaseDiffVoList = new ArrayList<>();
        methodDiff.setPhaseList(phaseDiffVoList);
        Map<Long, MethodPhase> diffPhaseCache = new HashMap<>();
        if (!CollectionUtils.isEmpty(diffPhaseList)) {
            diffPhaseCache = diffPhaseList.stream().collect(Collectors.toMap(MethodPhase::getId, phase -> phase));
        }
        for (int i = 0; i < currentPhaseList.size(); i++) {
            MethodPhase currentPhase = currentPhaseList.get(i);
            MethodPhaseDiffVo phaseDiffVo = new MethodPhaseDiffVo();
            Optional<MethodPhase> diffPhaseOpt = diffPhaseList.stream().filter(p -> p.getSourcePhaseId() != null && p.getSourcePhaseId().equals(currentPhase.getSourcePhaseId())).findFirst();
            if (diffPhaseOpt.isPresent()) {
                phaseDiffVo.setOtherSort(diffPhaseOpt.get().getSort());
            }
            if (currentPhase.getIsDelete().equals(BoolEnum.FALSE.getValue())) {
                DiffVo phaseNameDiffVo = new DiffVo();
                phaseDiffVo.setName(phaseNameDiffVo);
                phaseNameDiffVo.setCurrent(currentPhase.getName());
                DiffVo phaseTipVo = new DiffVo();
                phaseTipVo.setCurrent(currentPhase.getTip());
                phaseDiffVo.setTip(phaseTipVo);
                phaseDiffVo.setSort(currentPhase.getSort());
                List<MethodStep> thisCurrentStepList = currentStepList.stream().filter(s -> s.getMethodPhaseId().equals(currentPhase.getId())).collect(Collectors.toList());
                //if (!CollectionUtils.isEmpty(thisCurrentStepList)) {
                //    thisCurrentStepList.sort((a, b) -> {
                //        int r = a.getSort() - b.getSort();
                //        if (r == 0) {
                //            return b.getIsDelete() - a.getIsDelete();
                //        }
                //        return r;
                //    });
                //}
                if (diffPhaseOpt.isPresent() && diffPhaseOpt.get().getIsDelete().equals(BoolEnum.FALSE.getValue())) {
                    phaseDiffVo.setDiffType(MethodDiffEnum.Equal.getType());
                    if (!StringUtils.isEmpty(currentPhase.getName()) && !StringUtils.isEmpty(diffPhaseOpt.get().getName()) && !currentPhase.getName().equals(diffPhaseOpt.get().getName())) {
                        phaseNameDiffVo.setOther(diffPhaseOpt.get().getName());
                        phaseNameDiffVo.setDiffType(MethodDiffEnum.Edit.getType());
                        phaseDiffVo.setDiffType(MethodDiffEnum.Edit.getType());
                    } else if ((StringUtils.isEmpty(currentPhase.getName()) && !StringUtils.isEmpty(diffPhaseOpt.get().getName())) || (StringUtils.isEmpty(diffPhaseOpt.get().getName()) && !StringUtils.isEmpty(currentPhase.getName()))) {
                        phaseNameDiffVo.setOther(diffPhaseOpt.get().getName());
                        phaseNameDiffVo.setDiffType(MethodDiffEnum.Edit.getType());
                        phaseDiffVo.setDiffType(MethodDiffEnum.Edit.getType());
                    }
                    if (!StringUtils.isEmpty(currentPhase.getTip()) && !StringUtils.isEmpty(diffPhaseOpt.get().getTip()) && !currentPhase.getTip().equals(diffPhaseOpt.get().getTip())) {
                        phaseTipVo.setOther(diffPhaseOpt.get().getTip());
                        phaseTipVo.setDiffType(MethodDiffEnum.Edit.getType());
                        phaseDiffVo.setDiffType(MethodDiffEnum.Edit.getType());
                    } else if ((StringUtils.isEmpty(currentPhase.getTip()) && !StringUtils.isEmpty(diffPhaseOpt.get().getTip())) || (StringUtils.isEmpty(diffPhaseOpt.get().getTip()) && !StringUtils.isEmpty(currentPhase.getTip()))) {
                        phaseTipVo.setOther(diffPhaseOpt.get().getTip());
                        phaseTipVo.setDiffType(MethodDiffEnum.Edit.getType());
                        phaseDiffVo.setDiffType(MethodDiffEnum.Edit.getType());
                    }
                    List<MethodStep> diffThisStepList = diffStepList.stream().filter(ds -> ds.getMethodPhaseId().equals(diffPhaseOpt.get().getId())).collect(Collectors.toList());
                    List<MethodStepDiffVo> diffStepVoList = getStepDiffList(thisCurrentStepList, diffThisStepList, isPrevious);
                    phaseDiffVo.setStepList(diffStepVoList);
                } else {
                    if (isPrevious) {
                        phaseDiffVo.setDiffType(MethodDiffEnum.Add.getType());
                    } else {
                        phaseDiffVo.setDiffType(MethodDiffEnum.OtherDel.getType());
                    }
                    List<MethodStepDiffVo> diffStepVoList = getStepDiffList(thisCurrentStepList, new ArrayList<>(), isPrevious);
                    phaseDiffVo.setStepList(diffStepVoList);
                }
                phaseDiffVoList.add(phaseDiffVo);
            } else {
                if (diffPhaseOpt.isPresent() && diffPhaseOpt.get().getIsDelete().equals(BoolEnum.FALSE.getValue())) {
                    if (isPrevious) {
                        phaseDiffVo.setDiffType(MethodDiffEnum.Del.getType());
                    } else {
                        phaseDiffVo.setDiffType(MethodDiffEnum.OtherAdd.getType());
                    }
                    MethodPhaseDiffOtherVo other = new MethodPhaseDiffOtherVo();
                    phaseDiffVo.setOther(other);
                    phaseDiffVo.setOtherSort(diffPhaseOpt.get().getSort());
                    other.setName(diffPhaseOpt.get().getName());
                    other.setSort(diffPhaseOpt.get().getSort());
                    other.setTip(diffPhaseOpt.get().getTip());
                    List<MethodStepDiffOtherVo> otherStepList = new ArrayList<>();
                    other.setStepList(otherStepList);
                    List<MethodStep> diffThisStepList = diffStepList.stream().filter(ds -> ds.getMethodPhaseId().equals(diffPhaseOpt.get().getId())).collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(diffThisStepList)) {
                        diffThisStepList.forEach(s -> {
                            MethodStepDiffOtherVo otherStepVo = new MethodStepDiffOtherVo();
                            otherStepVo.setContent(s.getContent().replaceAll("#\\$\\{\\[reagent\\]<[a-z0-9]+>\\}\\$#", "").replaceAll("#\\$\\{\\[timer\\]<[a-z0-9]+>\\}\\$#", ""));
                            otherStepVo.setSort(s.getSort());
                            otherStepList.add(otherStepVo);
                        });
                    }
                    if (!CollectionUtils.isEmpty(other.getStepList())) {
                        other.getStepList().sort((x, y) -> {
                            if (x.getSort() != null && y.getSort() != null) {
                                return x.getSort() - y.getSort();
                            } else {
                                return -1;
                            }
                        });
                    }
                    phaseDiffVoList.add(phaseDiffVo);
                }
            }
            if (diffPhaseOpt.isPresent()) {
                diffPhaseCache.remove(diffPhaseOpt.get().getId());
            }
            if (!CollectionUtils.isEmpty(phaseDiffVo.getStepList())) {
                phaseDiffVo.getStepList().sort((x, y) -> {
                    if (x.getOtherSort() != null && y.getOtherSort() != null) {
                        return x.getOtherSort() - y.getOtherSort();
                    } else {
                        return x.getSort() - y.getSort();
                    }
                    //return -1;
                });
            }
        }
        if (!CollectionUtils.isEmpty(diffPhaseCache)) {
            diffPhaseCache.entrySet().forEach(set -> {
                if (set.getValue().getIsDelete().equals(BoolEnum.FALSE.getValue())) {
                    MethodPhaseDiffVo phaseDiffVo = new MethodPhaseDiffVo();
                    phaseDiffVo.setOtherSort(set.getValue().getSort());
                    phaseDiffVoList.add(phaseDiffVo);
                    MethodPhase diffPhase = set.getValue();
                    if (isPrevious) {
                        phaseDiffVo.setDiffType(MethodDiffEnum.Del.getType());
                    } else {
                        phaseDiffVo.setDiffType(MethodDiffEnum.OtherAdd.getType());
                    }
                    MethodPhaseDiffOtherVo other = new MethodPhaseDiffOtherVo();
                    phaseDiffVo.setOther(other);
                    other.setName(diffPhase.getName());
                    other.setSort(diffPhase.getSort());
                    other.setTip(diffPhase.getTip());
                    List<MethodStepDiffOtherVo> otherStepList = new ArrayList<>();
                    other.setStepList(otherStepList);
                    List<MethodStep> diffThisStepList = diffStepList.stream().filter(ds -> ds.getMethodPhaseId().equals(diffPhase.getId())).collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(diffThisStepList)) {
                        diffThisStepList.forEach(s -> {
                            MethodStepDiffOtherVo otherStepVo = new MethodStepDiffOtherVo();
                            otherStepVo.setContent(s.getContent().replaceAll("#\\$\\{\\[reagent\\]<[a-z0-9]+>\\}\\$#", "").replaceAll("#\\$\\{\\[timer\\]<[a-z0-9]+>\\}\\$#", ""));
                            otherStepVo.setSort(s.getSort());
                            otherStepList.add(otherStepVo);
                        });
                    }
                }
            });
        }
        methodDiff.getPhaseList().sort((x, y) -> {
            if (x.getOtherSort() != null && y.getOtherSort() != null) {
                return x.getOtherSort() - y.getOtherSort();
            } else if (x.getSort() != null && y.getSort() != null) {
                return x.getSort() - y.getSort();
            } else {
                return 1;
            }
        });
        return methodDiff;
    }

    public MethodSameSourceDiffVo sameSourceDiff(Long methodId, Long otherMethodId, UserInfoVo user) {
        Method method = methodService.getById(methodId);
        Method otherMethod = methodService.getById(otherMethodId);
        Assert.isTrue(method != null && otherMethod != null, "数据不存在");
        return sameSourceMethodDiff(false, user, method, otherMethod);
    }

    private List<MethodStepDiffVo> getStepDiffList(List<MethodStep> currentStepList, List<MethodStep> diffStepList, boolean isPrevious) {
        List<MethodStepDiffVo> diffVoList = new ArrayList<>();
        Integer max = Integer.max(currentStepList.size(), diffStepList.size());
        Map<Long, MethodStep> stepIdMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(diffStepList)) {
            stepIdMap = diffStepList.stream().collect(Collectors.toMap(MethodStep::getId, step -> step));
        }
        for (int i = 0; i < max; i++) {
            MethodStepDiffVo vo = new MethodStepDiffVo();
            MethodStep currentStep = null;
            MethodStep diffStep = null;
            boolean inCurrent = (!CollectionUtils.isEmpty(currentStepList)) && i < currentStepList.size();
            if (inCurrent) {
                currentStep = currentStepList.get(i);
                Long currenSourceSteptId = currentStep.getSourceStepId();
                if (!CollectionUtils.isEmpty(diffStepList)) {
                    Optional<MethodStep> diffStepOpt = diffStepList.stream().filter(f -> currenSourceSteptId.equals(f.getSourceStepId())).findFirst();
                    if (diffStepOpt.isPresent()) {
                        diffStep = diffStepOpt.get();
                        stepIdMap.remove(diffStep.getId());
                    }
                }
                if (currentStep.getIsDelete().equals(BoolEnum.FALSE.getValue())) {
                    DiffVo stepDiffVo = new DiffVo();
                    stepDiffVo.setCurrent(currentStep.getContent().replaceAll("#\\$\\{\\[reagent\\]<[a-z0-9]+>\\}\\$#", "").replaceAll("#\\$\\{\\[timer\\]<[a-z0-9]+>\\}\\$#", ""));
                    if (diffStep != null && !StringUtils.isEmpty(currentStep.getContent()) && !StringUtils.isEmpty(diffStep.getContent()) && !currentStep.getContent().replaceAll("#\\$\\{\\[reagent\\]<[a-z0-9]+>\\}\\$#", "").replaceAll("#\\$\\{\\[timer\\]<[a-z0-9]+>\\}\\$#", "").equals(diffStep.getContent().replaceAll("#\\$\\{\\[reagent\\]<[a-z0-9]+>\\}\\$#", "").replaceAll("#\\$\\{\\[timer\\]<[a-z0-9]+>\\}\\$#", ""))) {
                        stepDiffVo.setOther(diffStep.getContent().replaceAll("#\\$\\{\\[reagent\\]<[a-z0-9]+>\\}\\$#", "").replaceAll("#\\$\\{\\[timer\\]<[a-z0-9]+>\\}\\$#", ""));
                        stepDiffVo.setDiffType(MethodDiffEnum.Edit.getType());
                    } else if (diffStep != null && (!StringUtils.isEmpty(currentStep.getContent()) && StringUtils.isEmpty(diffStep.getContent()) || StringUtils.isEmpty(currentStep.getContent()) && !StringUtils.isEmpty(diffStep.getContent()))) {
                        stepDiffVo.setOther(diffStep.getContent().replaceAll("#\\$\\{\\[reagent\\]<[a-z0-9]+>\\}\\$#", "").replaceAll("#\\$\\{\\[timer\\]<[a-z0-9]+>\\}\\$#", ""));
                        stepDiffVo.setDiffType(MethodDiffEnum.Edit.getType());
                    } else if (diffStep != null && diffStep.getIsDelete().equals(BoolEnum.TRUE.getValue())) {
                        stepDiffVo.setDiffType(MethodDiffEnum.OtherDel.getType());
                    } else if (diffStep == null) {
                        if (isPrevious) {
                            stepDiffVo.setDiffType(MethodDiffEnum.Add.getType());
                        } else {
                            stepDiffVo.setDiffType(MethodDiffEnum.OtherDel.getType());
                        }
                    }
                    if (diffStep != null) {
                        vo.setOtherSort(diffStep.getSort());
                    }
                    vo.setContent(stepDiffVo);
                    vo.setSort(currentStep.getSort());
                    diffVoList.add(vo);
                } else {
                    if (diffStep != null && diffStep.getIsDelete().equals(BoolEnum.FALSE.getValue())) {
                        DiffVo stepDiffVo = new DiffVo();
                        stepDiffVo.setOther(diffStep.getContent().replaceAll("#\\$\\{\\[reagent\\]<[a-z0-9]+>\\}\\$#", "").replaceAll("#\\$\\{\\[timer\\]<[a-z0-9]+>\\}\\$#", ""));
                        stepDiffVo.setDiffType(MethodDiffEnum.Del.getType());
                        vo.setContent(stepDiffVo);
                        vo.setSort(currentStep.getSort());
                        vo.setOtherSort(diffStep.getSort());
                        diffVoList.add(vo);
                    }
                }
            }
        }
        if (!stepIdMap.isEmpty()) {
            stepIdMap.entrySet().forEach(set -> {
                if (set.getValue().getIsDelete().equals(BoolEnum.FALSE.getValue())) {
                    MethodStepDiffVo vo = new MethodStepDiffVo();
                    DiffVo stepDiffVo = new DiffVo();
                    vo.setContent(stepDiffVo);
                    vo.setSort(set.getValue().getSort());
                    vo.setOtherSort(set.getValue().getSort());
                    stepDiffVo.setOther(set.getValue().getContent().replaceAll("#\\$\\{\\[reagent\\]<[a-z0-9]+>\\}\\$#", "").replaceAll("#\\$\\{\\[timer\\]<[a-z0-9]+>\\}\\$#", ""));
                    stepDiffVo.setDiffType(MethodDiffEnum.OtherAdd.getType());
                    diffVoList.add(vo);
                }
            });
        }
        diffVoList.sort((x, y) -> {
            if (x.getOtherSort() != null && y.getOtherSort() != null) {
                return x.getOtherSort() - y.getOtherSort();
            }
            return -1;
        });
        return diffVoList;
    }

    public boolean delete(Long methodId, UserInfoVo user) {
        Method method = methodService.getById(methodId);
        Assert.notNull(method, "数据不存在");
        Assert.isTrue(user.getId().equals(method.getUserId()), "无权限");
        methodRecommendAuditService.deleteNotAudit(method.getId());
        methodShareService.deleteNotDeal(method.getId());
        return methodService.delete(method.getInitMethodId(), user.getId());
    }

    public List<MethodDeleteListItem> getDeleteList(Long userId) {
        List<Method> list = methodService.getMethodListByUserIdAndState(userId, BoolEnum.TRUE, null,false);
        List<MethodType> all = methodTypeService.getUserAllThirdTypeList(userId);
        List<MethodDeleteListItem> result = list.stream().map(i -> new MethodDeleteListItem(i.getId(), i.getName(),all.stream().filter(t->t.getId().equals(i.getMethodTypeId())).findFirst().get().getFirstId(), i.getUpdateTime())).collect(Collectors.toList());
        return result;
    }

    /**
     * @return void
     * @Description: 管理员审核通过推荐保存到自己的方法
     * @Params: [user, myThird, method]
     * @author wuzhiyu
     * @date 2019/3/12 14:15
     */
    public void methodLabViewAndTypeUsage(UserInfoVo user, MethodType myThird, Method method) {
        MethodLabView view = new MethodLabView();
        view.setCurrentMethodId(method.getId());
        view.setFirstMethodTypeId(myThird.getFirstId());
        view.setInitMethodId(method.getId());
        view.setLabId(user.getLabId());
        view.setLabMemberId(user.getLabMemberId());
        view.setThirdMethodTypeId(myThird.getId());
        view.setThirdMethodTypeName(myThird.getName());
        view.setUserId(user.getId());
        methodLabViewService.save(view);
        methodTypeUseService.insertOrUpdateThirdMethodTypeUse(method.getMethodTypeId(), user.getId(),MethodTypeUseTypeEnum.ADD_METHOD);
    }

    public boolean methodAttachFileDeal(Long[] newAttachIdList, List<Long> copyAttachtIdList, UserInfoVo user, Long methodId) {
        if (newAttachIdList != null && newAttachIdList.length > 0) {
            //fixme 附件处理
            fileManageService.relevanceBatch(newAttachIdList, methodId, OssFileEnum.Method, null, user.getId());
        }
        if (!CollectionUtils.isEmpty(copyAttachtIdList)) {
            //fixme 附件处理  oss需要改动
            List<FileManage> fileList = fileManageService.listByIdList(copyAttachtIdList);
            if (!CollectionUtils.isEmpty(fileList)) {
                List<FileManage> copies = new ArrayList<>();
                fileList.forEach(fileManage -> {
                    fileManage.setId(null);
                    fileManage.setReferDataId(methodId);
                    fileManage.setUserId(user.getId());
                    fileManage.setAttachType(OssFileEnum.Method.getKey());
                    fileManage.setLabId(null);
                    fileManage.setCreateTime(null);
                    copies.add(fileManage);
                });
                fileManageService.insertBatch(copies);
            }
        }
        return true;
    }

    public Long updateOrNewVersion(NewMethod newMethod, UserInfoVo user) {
        Assert.notNull(newMethod.getId(), "数据缺失");
        MethodDetail methodDetail = getMethodDetail(newMethod.getId(), null, user.getLabId());
        MethodUpdate update = new MethodUpdate();
        boolean isUpdate = false;
        Long id = newMethod.getId();
        update.setId(newMethod.getId());
        if (!StringUtils.isEmpty(newMethod.getName()) && !newMethod.getName().equals(methodDetail.getName())) {
            update.setName(newMethod.getName());
            isUpdate = true;
        }
        if (newMethod.getAuthor() != null && !newMethod.getAuthor().equals(methodDetail.getAuthor())) {
            update.setAuthor(newMethod.getAuthor());
            isUpdate = true;
        }
        if (newMethod.getMethodTypeId() != null && !newMethod.getMethodTypeId().equals(methodDetail.getMethodTypeId())) {
            update.setMethodTypeId(newMethod.getMethodTypeId());
            isUpdate = true;
        }
        if (newMethod.getDescription() != null && !newMethod.getDescription().equals(methodDetail.getDescription())) {
            update.setDescription(newMethod.getDescription());
            isUpdate = true;
        }
        if (newMethod.getLink() != null && !newMethod.getLink().equals(methodDetail.getLink())) {
            update.setLink(newMethod.getLink());
            isUpdate = true;
        }
        boolean isNewVersion = false;
        if (CollectionUtils.isEmpty(methodDetail.getPhaseList()) || CollectionUtils.isEmpty(newMethod.getPhaseList())) {
            int dSize = CollectionUtils.isEmpty(methodDetail.getPhaseList()) ? 0 : methodDetail.getPhaseList().size();
            int nSize = CollectionUtils.isEmpty(newMethod.getPhaseList()) ? 0 : newMethod.getPhaseList().size();
            if (dSize != nSize) {
                isNewVersion = true;
            } else {
                if (dSize != 0 && nSize != 0) {
                    Long dDelCnt = methodDetail.getPhaseList().stream().filter(p -> BoolEnum.FALSE.getValue().equals(p.getIsDelete())).count();
                    Long nDelCnt = newMethod.getPhaseList().stream().filter(p -> BoolEnum.FALSE.getValue().equals(p.getIsDelete())).count();
                    if (!dDelCnt.equals(nDelCnt)) {
                        isNewVersion = true;
                    }
                }
            }
        } else {
            if (methodDetail.getPhaseList().size() != newMethod.getPhaseList().size()) {
                isNewVersion = true;
            } else {
                for (MethodPhaseDetail dp : methodDetail.getPhaseList()) {
                    NewMethodPhase np = newMethod.getPhaseList().stream().filter(p ->
                            p.getId().equals(dp.getId())
                    ).findFirst().get();
                    if (np.getIsDelete().equals(dp.getIsDelete())) {
                        if ((dp.getName() != null && dp.getName().equals(np.getName())) || (dp.getName() == null && np.getName() == null)) {
                            if (dp.getSort().equals(np.getSort())) {
                                if ((dp.getTip() != null && dp.getTip().equals(np.getTip()) || (dp.getTip() == null && np.getTip() == null))) {
                                    if (CollectionUtils.isEmpty(dp.getStepList()) || CollectionUtils.isEmpty(np.getStepList())) {
                                        int dSize = CollectionUtils.isEmpty(dp.getStepList()) ? 0 : dp.getStepList().size();
                                        int nSize = CollectionUtils.isEmpty(np.getStepList()) ? 0 : np.getStepList().size();
                                        if (dSize != nSize) {
                                            isNewVersion = true;
                                        } else {
                                            if (dSize != 0 && nSize != 0) {
                                                Long dDelCnt = dp.getStepList().stream().filter(p -> BoolEnum.FALSE.equals(p.getIsDelete())).count();
                                                Long nDelCnt = np.getStepList().stream().filter(p -> BoolEnum.FALSE.equals(p.getIsDelete())).count();
                                                if (!dDelCnt.equals(nDelCnt)) {
                                                    isNewVersion = true;
                                                }
                                            }
                                        }
                                    } else {
                                        if (dp.getStepList().size() != np.getStepList().size()) {
                                            isNewVersion = true;
                                        } else {
                                            for (MethodStepDetail dSd : dp.getStepList()) {
                                                NewMethodStep nSd = np.getStepList().stream().filter(ns -> ns.getId().equals(dSd.getId())).findFirst().get();
                                                if (dSd.getIsDelete().equals(nSd.getIsDelete())) {
                                                    if (dSd.getSort().equals(nSd.getSort())) {
                                                        if ((dSd.getContent() != null && !dSd.getContent().equals(nSd.getContent())) || (dSd.getContent() == null && nSd.getContent() != null)) {
                                                            isNewVersion = true;
                                                        }
                                                    } else {
                                                        isNewVersion = true;
                                                    }
                                                } else {
                                                    isNewVersion = true;
                                                }
                                            }
                                        }
                                    }
                                } else {
                                    isNewVersion = true;
                                }
                            } else {
                                isNewVersion = true;
                            }
                        } else {
                            isNewVersion = true;
                        }
                    } else {
                        isNewVersion = true;
                    }
                    if (isNewVersion) {
                        break;
                    }
                }
            }
        }
        if (isNewVersion) {
            id = addNewVersion(newMethod, user);
            return id;
        } else if (isUpdate) {
            id = update.getId();
            methodService.update(update, user);
        }
        //fixme 附件处理
        if (newMethod.getUploadFileIdList() != null && newMethod.getUploadFileIdList().length > 0) {
            fileManageService.relevanceBatch(newMethod.getUploadFileIdList(), id, OssFileEnum.Method, null, user.getId());
        }
        return id;
    }

    public Long saveAcceptMethodToNewVersion(UserInfoVo user, Method oriMethod, Long saveToInitMethodId, Date fromTime) {
        Method existMethod = methodService.getById(saveToInitMethodId);
        Assert.notNull(existMethod, "数据不存在");
        Assert.isTrue(existMethod.getUserId().equals(user.getId()), "数据不存在");
        MethodType myThirdType = findMyThirdMethodTypeAndShow(user.getId(), existMethod.getMethodTypeId(), true);
        List<MethodPhase> myPhaseList = methodPhaseService.listByMethodId(saveToInitMethodId, null);
        List<MethodStep> myStepList = methodStepService.listByMethodId(saveToInitMethodId, null);
        List<MethodPhase> sourcePhaseList = methodPhaseService.listByMethodId(oriMethod.getId(), null);
        List<MethodStep> sourceStepList = methodStepService.listByMethodId(oriMethod.getId(), null);
        List<MethodRelateReagent> sourceRelateReagentList = methodRelateReagentService.listMethodRelateReagentByMethodId(oriMethod.getId());
        List<MethodRelateTimer> sourceRelateTimerList = methodRelateTimerService.getByMethodId(oriMethod.getId());
        Users shareUser = usersService.selectUser(oriMethod.getUserId(), null);
        Integer maxVersion = methodService.getCurrentMaxVersion(saveToInitMethodId);

        MethodFullInfo existInfo = composeMethodFullInfo(existMethod, myPhaseList, myStepList, null, null);
        MethodFullInfo sourceInfo = composeMethodFullInfo(oriMethod, sourcePhaseList, sourceStepList, sourceRelateReagentList, sourceRelateTimerList);
        MethodSaveDto saveDto = new MethodSaveDto(existInfo, sourceInfo, MethodSourceEnum.SHARE, shareUser.getName(), fromTime, false, null, myThirdType, user, maxVersion + 1);
        Method method = copyToMyMethod(saveDto);
        return method.getId();
    }

    public boolean sameNameAndType(Long thirdTypeId, String metodName, UserInfoVo user) {
        List<Method> methodList = methodService.getByThirdTypeIdAndMethodNameAndUserId(thirdTypeId, metodName, user.getId());
        return !CollectionUtils.isEmpty(methodList);
    }

    public List<MethodPhaseDetail> convertMethod(String textContent) {
        List<MethodPhaseDetail> methodPhaseDetailList = new ArrayList<>();
        if (StringUtils.isEmpty(textContent)) {
            return methodPhaseDetailList;
        }
        textContent = textContent.replaceAll("\r", "");
        List<ConvertDTO> dtoList = new ArrayList<>();
        for (ConvertMainSignType main : ConvertMainSignType.values()) {
            for (ConvertSignType sign : ConvertSignType.values()) {
                ConvertDTO dto = new ConvertDTO(main, sign);
                for (int i = 0; i < dto.getMainSignList().size(); i++) {
                    dto.getIndexInfo(textContent, i);
                }
                dtoList.add(dto);
            }
        }
        List<ConvertDTO> result = dtoList.stream().filter(d -> !CollectionUtils.isEmpty(d.getIndexInfoList())).sorted((x, y) -> x.getIndexInfoList().get(0).getIndex() - y.getIndexInfoList().get(0).getIndex()).collect(Collectors.toList());
        if (result.size() == 1) {
            ConvertDTO dto = result.get(0);
            MethodPhaseDetail methodPhaseDetail = new MethodPhaseDetail();
            methodPhaseDetailList.add(methodPhaseDetail);
            List<MethodStepDetail> methodStepDetailList = new ArrayList<>();
            methodPhaseDetail.setStepList(methodStepDetailList);
            setPhaseDtoInfo(textContent, methodPhaseDetail, new ConvertDTO(ConvertMainSignType.INT, ConvertSignType.DOT), dto);
            getStepConvertDto(textContent, dto, null, methodStepDetailList);
        } else if (result.size() > 1) {
            ConvertDTO first = result.get(0);
            ConvertDTO second = result.get(1);
            if (first.getIndexInfoList().size() == 1) {
                MethodPhaseDetail methodPhaseDetail = new MethodPhaseDetail();
                methodPhaseDetailList.add(methodPhaseDetail);
                setPhaseDtoInfo(textContent, methodPhaseDetail, first, second);
                List<MethodStepDetail> methodStepDetailList = new ArrayList<>();
                methodPhaseDetail.setStepList(methodStepDetailList);
                getStepConvertDto(textContent, second, null, methodStepDetailList);
            } else {
                for (int i = 0; i < first.getIndexInfoList().size(); i++) {
                    IndexInfo start = first.getIndexInfoList().get(i);
                    IndexInfo end = getEndIndexInfo(textContent, first, i);
                    String thisStr = textContent.substring(start.getIndex(), end.getIndex());
                    if (thisStr.startsWith("\n")) {
                        thisStr = thisStr.replaceFirst("\\s+", "");
                    }
                    MethodPhaseDetail methodPhaseDetail = new MethodPhaseDetail();
                    methodPhaseDetailList.add(methodPhaseDetail);
                    List<MethodStepDetail> methodStepDetailList = new ArrayList<>();
                    methodPhaseDetail.setStepList(methodStepDetailList);
                    /**********************单层*******************/
                    //ConvertDTO stepDto = new ConvertDTO(first.getMainSignType(), first.getSignType());
                    //stepDto.regetIndexInfo(thisStr);
                    //getStepConvertDto(thisStr, stepDto, phaseDto, methodStepDetailList);
                    /****************两层**************/
                    ConvertDTO phaseDto = new ConvertDTO(first.getMainSignType(), first.getSignType());
                    phaseDto.regetIndexInfo(thisStr);
                    ConvertDTO stepDto;
                    List<ConvertDTO> stepDtoList = new ArrayList<>();
                    for (ConvertMainSignType main : ConvertMainSignType.values()) {
                        for (ConvertSignType sign : ConvertSignType.values()) {
                            if (main.equals(first.getMainSignType()) && sign.equals(first.getSignType())) {

                            } else {
                                ConvertDTO dto = new ConvertDTO(main, sign);
                                for (int x = 0; x < dto.getMainSignList().size(); x++) {
                                    dto.getIndexInfo(thisStr, x);
                                }
                                stepDtoList.add(dto);
                            }
                        }
                    }
                    List<ConvertDTO> resultStep = stepDtoList.stream().filter(d -> !CollectionUtils.isEmpty(d.getIndexInfoList())).sorted((x, y) -> x.getIndexInfoList().get(0).getIndex() - y.getIndexInfoList().get(0).getIndex()).collect(Collectors.toList());
                    if (resultStep.size() > 0) {
                        stepDto = resultStep.get(0);
                    } else {
                        stepDto = new ConvertDTO(second.getMainSignType(), second.getSignType());
                        stepDto.regetIndexInfo(thisStr);
                    }
                    setPhaseDtoInfo(thisStr, methodPhaseDetail, phaseDto, stepDto);
                    getStepConvertDto(thisStr, stepDto, phaseDto, methodStepDetailList);
                }
            }
        } else {
            MethodPhaseDetail methodPhaseDetail = new MethodPhaseDetail();
            methodPhaseDetailList.add(methodPhaseDetail);
            List<MethodStepDetail> methodStepDetailList = new ArrayList<>();
            MethodStepDetail step = new MethodStepDetail();
            step.setContent(textContent);
            methodStepDetailList.add(step);
            methodPhaseDetail.setStepList(methodStepDetailList);
        }
        for(MethodPhaseDetail d :methodPhaseDetailList){
            for (MethodStepDetail sd :d.getStepList()){
                if(sd.getContent()!=null){
                    sd.setContent(sd.getContent().trim());
                }
            }
        }
        return methodPhaseDetailList;
    }

    private void setPhaseDtoInfo(String thisStr, MethodPhaseDetail methodPhaseDetail, ConvertDTO phaseDto, ConvertDTO stepDto) {
        Integer firstNewLineIndex = thisStr.indexOf("\n");
        Integer oldLength = thisStr.length();
        Integer lenDiff = 0;
        if (firstNewLineIndex > -1 && phaseDto.getIndexInfoList().size() > 0 && firstNewLineIndex < phaseDto.getIndexInfoList().get(0).getIndex()) {
            thisStr = thisStr.replaceFirst("\\s+", "");
            lenDiff = oldLength - thisStr.length();
        }
        firstNewLineIndex = thisStr.indexOf("\n");
        if (phaseDto.getIndexInfoList().size() > 1) {
            if (stepDto.getIndexInfoList().size() > 0) {
                if (firstNewLineIndex > -1 && firstNewLineIndex < (stepDto.getIndexInfoList().get(0).getIndex() - lenDiff)) {
                    methodPhaseDetail.setName(thisStr.substring(phaseDto.getIndexInfoList().get(0).getIndex() - lenDiff + phaseDto.getIndexInfoList().get(0).getSignLength(), firstNewLineIndex));
                    methodPhaseDetail.setTip(thisStr.substring(firstNewLineIndex, stepDto.getIndexInfoList().get(0).getIndex() - lenDiff));
                } else {
                    methodPhaseDetail.setName(thisStr.substring(phaseDto.getIndexInfoList().get(0).getIndex() - lenDiff + phaseDto.getIndexInfoList().get(0).getSignLength(), stepDto.getIndexInfoList().get(0).getIndex() - lenDiff));
                }
            } else {
                if (firstNewLineIndex > -1 && firstNewLineIndex < (phaseDto.getIndexInfoList().get(1).getIndex() - lenDiff)) {
                    methodPhaseDetail.setName(thisStr.substring(phaseDto.getIndexInfoList().get(0).getIndex() - lenDiff + phaseDto.getIndexInfoList().get(0).getSignLength(), firstNewLineIndex));
                    //methodPhaseDetail.setTip(thisStr.substring(firstNewLineIndex, phaseDto.getIndexInfoList().get(1).getIndex() - lenDiff));
                    MethodStepDetail step = new MethodStepDetail();
                    step.setContent(thisStr.substring(firstNewLineIndex, phaseDto.getIndexInfoList().get(1).getIndex() - lenDiff));
                    methodPhaseDetail.getStepList().add(step);
                } else {
                    methodPhaseDetail.setName(thisStr.substring(phaseDto.getIndexInfoList().get(0).getIndex() - lenDiff + phaseDto.getIndexInfoList().get(0).getSignLength(), phaseDto.getIndexInfoList().get(1).getIndex() - lenDiff));
                }
            }
        } else if (phaseDto.getIndexInfoList().size() == 1) {
            if (stepDto.getIndexInfoList().size() > 0) {
                if (firstNewLineIndex > -1 && firstNewLineIndex < (stepDto.getIndexInfoList().get(0).getIndex() - lenDiff)) {
                    methodPhaseDetail.setName(thisStr.substring(phaseDto.getIndexInfoList().get(0).getIndex() - lenDiff + phaseDto.getIndexInfoList().get(0).getSignLength(), firstNewLineIndex));
                    methodPhaseDetail.setTip(thisStr.substring(firstNewLineIndex, stepDto.getIndexInfoList().get(0).getIndex() - lenDiff));
                } else {
                    methodPhaseDetail.setName(thisStr.substring(phaseDto.getIndexInfoList().get(0).getIndex() - lenDiff + phaseDto.getIndexInfoList().get(0).getSignLength(), stepDto.getIndexInfoList().get(0).getIndex() - lenDiff));
                }
            } else {
                if (firstNewLineIndex > -1 && firstNewLineIndex < thisStr.length()) {
                    if (phaseDto.getIndexInfoList().get(0).getIndex() - lenDiff + phaseDto.getIndexInfoList().get(0).getSignLength() < firstNewLineIndex) {
                        methodPhaseDetail.setName(thisStr.substring(phaseDto.getIndexInfoList().get(0).getIndex() - lenDiff + phaseDto.getIndexInfoList().get(0).getSignLength(), firstNewLineIndex));
                    } else {
                        methodPhaseDetail.setName(thisStr.substring(0, firstNewLineIndex));
                    }
                    MethodStepDetail step = new MethodStepDetail();
                    step.setContent(thisStr.substring(firstNewLineIndex));
                    methodPhaseDetail.getStepList().add(step);
                } else {
                    methodPhaseDetail.setName(thisStr.substring(phaseDto.getIndexInfoList().get(0).getIndex() - lenDiff + phaseDto.getIndexInfoList().get(0).getSignLength()));
                }
            }
        } else {
            if (stepDto.getIndexInfoList().size() > 0) {
                if (firstNewLineIndex > -1 && firstNewLineIndex < (stepDto.getIndexInfoList().get(0).getIndex() - lenDiff)) {
                    methodPhaseDetail.setName(thisStr.substring(0, firstNewLineIndex));
                    methodPhaseDetail.setTip(thisStr.substring(firstNewLineIndex, stepDto.getIndexInfoList().get(0).getIndex() - lenDiff));
                } else {
                    methodPhaseDetail.setName(thisStr.substring(0, stepDto.getIndexInfoList().get(0).getIndex() - lenDiff));
                }
            } else {
                if (firstNewLineIndex > -1 && firstNewLineIndex < thisStr.length()) {
                    methodPhaseDetail.setName(thisStr.substring(0, firstNewLineIndex));
                    //methodPhaseDetail.setTip(thisStr.substring(firstNewLineIndex));
                    MethodStepDetail step = new MethodStepDetail();
                    step.setContent(thisStr.substring(firstNewLineIndex));
                    methodPhaseDetail.getStepList().add(step);
                } else {
                    methodPhaseDetail.setName(thisStr);
                }
            }
        }
    }

    private IndexInfo getEndIndexInfo(String textContent, ConvertDTO dto, int i) {
        IndexInfo end;
        if (i == dto.getIndexInfoList().size() - 1) {
            end = new IndexInfo();
            end.setIndex(textContent.length());
        } else {
            end = dto.getIndexInfoList().get(i + 1);
        }
        return end;
    }

    private void getStepConvertDto(String textContent, ConvertDTO stepDto, ConvertDTO
            phaseDto, List<MethodStepDetail> methodStepDetailList) {
        for (int i = 0; i < stepDto.getIndexInfoList().size(); i++) {
            IndexInfo start = stepDto.getIndexInfoList().get(i);
            IndexInfo end = getEndIndexInfo(textContent, stepDto, i);
            MethodStepDetail stepContentDto = new MethodStepDetail();
            String content = textContent.substring(start.getIndex(), end.getIndex());
            setStepContent(phaseDto, start, stepContentDto, content);
            methodStepDetailList.add(stepContentDto);
        }
    }

    private void setStepContent(ConvertDTO phaseDto, IndexInfo start, MethodStepDetail stepContentDto, String
            content) {
        String trimStr = content.replaceFirst("\\s+", "");
        if (phaseDto == null) {
            if (start.getSignLength() != null && start.getSignLength() < trimStr.length()) {
                stepContentDto.setContent(trimStr.substring(start.getSignLength()));
            } else {
                stepContentDto.setContent(trimStr);
            }
        } else {
            stepContentDto.setContent(trimStr.substring(start.getSignLength()));
        }
    }


    public MethodType findMyThirdMethodTypeAndShow(Long userId, Long methodTypeId, boolean hiddenToShow) {
        MethodType type = methodTypeService.getMethodTypeById(methodTypeId);
        Assert.isTrue(type != null && MethodTypeLevelEnum.LevelThird.getLevel().equals(type.getLevel()) && (userId.equals(type.getUserId()) || type.getUserId() == null), "数据不存在");
        if (hiddenToShow) {
            methodTypeLogic.showMethodType(type.getId(), userId);
        }
        return type;
    }

    /**
     * @return void
     * @Description: 参数为NewMethod保存为Method，会设置Method的version,current,isDelete
     * @Params: [newMethod, user, method, version, setInitNull]
     * @author wuzhiyu
     * @date 2019/4/26 16:02
     */
    public void setVersionUserIdCurrentDeleteAndSave(NewMethod newMethod, UserInfoVo user, Method method,
                                                     int version, boolean setInitNull) {
        method.setVersion(version);
        method.setUserId(user.getId());
        method.setCurrent(BoolEnum.TRUE.getValue());
        method.setIsDelete(BoolEnum.FALSE.getValue());
        method.setIsCommon(null);
        if (setInitNull) {
            method.setInitMethodId(null);
            methodService.saveMethodAndUpdateInitId(method);
        } else {
            methodService.save(method);
        }
        /**   参考方法导入次数有问题，先取消*/
        //if (MethodSourceEnum.IMPORT.getSourceType().equals(method.getFromType())) {
        //    if (newMethod.getSourceMethodId() != null) {
        //        methodService.increaseExportCount(newMethod.getSourceMethodId());
        //    }
        //}
        if (!CollectionUtils.isEmpty(newMethod.getPhaseList())) {
            newMethod.getPhaseList().forEach(p -> {
                saveNewPhase(method, p, setInitNull);
            });
        }
        //todo  附件处理
    }

    public void saveNewPhase(Method myMethod, NewMethodPhase newPhase, boolean setInitNull) {
        MethodPhase myPhase = new MethodPhase();
        BeanUtils.copyProperties(newPhase, myPhase);
        myPhase.setMethodId(myMethod.getId());
        if (newPhase.getInitPhaseId() == null) {
            methodPhaseService.savePhaseAndUpdateInitId(myPhase, myMethod.getFromType());
        } else {
            methodPhaseService.save(myPhase);
        }
        if (!CollectionUtils.isEmpty(newPhase.getStepList())) {
            newPhase.getStepList().forEach(s -> {
                if (setInitNull) {
                    s.setInitStepId(null);
                }
                saveNewStep(myMethod, myPhase, s);
            });
        }
    }

    public void saveNewStep(Method myMethod, MethodPhase myPhase, NewMethodStep newStep) {
        MethodStep myStep = new MethodStep();
        BeanUtils.copyProperties(newStep, myStep);
        myStep.setMethodPhaseId(myPhase.getId());
        myStep.setMethodId(myMethod.getId());
        if (newStep.getInitStepId() == null) {
            methodStepService.saveStepAndUpdateInitId(myStep, myMethod.getFromType());
        } else {
            methodStepService.save(myStep);
        }
        List<MethodRelateReagentVo> relateReagentVoList = newStep.getReagentVoList();
        if (!CollectionUtils.isEmpty(relateReagentVoList)) {
            List<MethodRelateReagent> relateReagentList = new ArrayList<>();
            relateReagentVoList.forEach(r -> {
                MethodRelateReagent reagent = new MethodRelateReagent();
                BeanUtils.copyProperties(r, reagent);
                reagent.setMethodId(myMethod.getId());
                reagent.setPhaseId(myPhase.getId());
                reagent.setStepId(myStep.getId());
                relateReagentList.add(reagent);
            });
            methodRelateReagentService.saveRelateReagentList(relateReagentList);
        }
        if (!CollectionUtils.isEmpty(newStep.getTimerList())) {
            saveMethodRelateTimerList(myMethod.getId(), myPhase.getId(), myStep.getId(), newStep.getTimerList());
        }
    }

    public MethodType getMyThirdTypeOrCreateNew(UserInfoVo user, Method oriMethod, Long mySelectedTypeId) {
        MethodType myThird = null;
        if (mySelectedTypeId == null) {
            myThird = findMyThirdTypeOrCreateNew(user.getId(), oriMethod.getMethodTypeId(), true, true);
        } else {
            myThird = methodTypeService.getMethodTypeById(mySelectedTypeId);
            Assert.notNull(myThird, "类型不存在");
        }
        return myThird;
    }


    /**
     * @return com.brillilab.domain.po.method.MethodType
     * @Description: 查找是否存在和别人的第三级类型相同的第三级类型，不存在是否新建，存在是否显示
     * @Params: [userId, otherMethodTypeId, createNewType, hiddenToShow]
     * @author wuzhiyu
     * @date 2019/4/29 13:36
     */
    public MethodType findMyThirdTypeOrCreateNew(Long userId, Long otherMethodTypeId, boolean createNewType,
                                                 boolean hiddenToShow) {
        MethodType myThird = null;
        List<MethodType> all = methodTypeService.listUserAllType(userId);
        List<MethodType> levels = methodTypeService.listThreeLevelTypeByThirdId(otherMethodTypeId);
        MethodType first = levels.stream().filter(o -> o.getLevel().equals(MethodTypeLevelEnum.LevelFirst.getLevel())).findFirst().get();
        MethodType second = levels.stream().filter(o -> o.getLevel().equals(MethodTypeLevelEnum.LevelSecond.getLevel())).findFirst().get();
        MethodType third = levels.stream().filter(o -> o.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel())).findFirst().get();
        //判断类型是否存在
        if (third.getUserId() != null) {
            //一级类型全部公共，可能相同名字二级类型在不同的一级类型下
            Optional<MethodType> secondOpt = all.stream().filter(s -> s.getLevel().equals(MethodTypeLevelEnum.LevelSecond.getLevel()) && s.getName().equals(second.getName()) && s.getFirstId().equals(first.getId())).findFirst();
            if (secondOpt.isPresent()) {
                Optional<MethodType> thirdOpt = all.stream().filter(t -> t.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel()) && t.getName().equals(third.getName()) && t.getSecondId().equals(secondOpt.get().getId())).findFirst();
                if (!thirdOpt.isPresent()) {
                    if (createNewType) {
                        MethodType newThird = saveThirdType(userId, first.getId(), secondOpt.get().getId(), third.getName());
                        myThird = newThird;
                    }
                } else {
                    myThird = thirdOpt.get();
                }
            } else {
                if (createNewType) {
                    MethodType newSec = new MethodType();
                    newSec.setName(second.getName());
                    newSec.setLevel(MethodTypeLevelEnum.LevelSecond.getLevel());
                    newSec.setFirstId(first.getId());
                    newSec.setIsDelete(BoolEnum.FALSE.getValue());
                    newSec.setUserId(userId);
                    newSec.setUseTime(new Date());
                    newSec.setVisible(BoolEnum.TRUE.getValue());
                    methodTypeService.add(newSec);
                    MethodType newThird = saveThirdType(userId, first.getId(), newSec.getId(), third.getName());
                    myThird = newThird;
                }
            }
        } else {
            myThird = third;
        }

        if (myThird != null) {
            methodTypeLogic.showMethodType(myThird.getId(), userId);
        }
        return myThird;
    }

    public MethodType saveThirdType(Long userId, Long firstId, Long secondId, String thirdName) {
        MethodType newThird = new MethodType();
        newThird.setVisible(BoolEnum.TRUE.getValue());
        newThird.setUseTime(new Date());
        newThird.setUserId(userId);
        newThird.setIsDelete(BoolEnum.FALSE.getValue());
        newThird.setFirstId(firstId);
        newThird.setLevel(MethodTypeLevelEnum.LevelThird.getLevel());
        newThird.setName(thirdName);
        newThird.setSecondId(secondId);
        methodTypeService.add(newThird);
        return newThird;
    }

    //保存实验为方法
    public Long saveExperimentToMethod(Long oriMethodId, MethodFullInfo sourceInfo, UserInfoVo
            user) {
        Method oriMehtod = methodService.getById(oriMethodId);
        List<MethodPhase> oriPhaseList = methodPhaseService.listByMethodId(oriMehtod.getId(), null);
        List<MethodStep> oriStepList = methodStepService.listByMethodId(oriMehtod.getId(), null);
        MethodFullInfo oriInfo = composeMethodFullInfo(oriMehtod, oriPhaseList, oriStepList, null, null);
        MethodType oriThirdType = findMyThirdMethodTypeAndShow(oriMehtod.getUserId(), oriMehtod.getMethodTypeId(), true);
        MethodSaveDto saveDto = new MethodSaveDto(oriInfo, sourceInfo, null, null, null, false, null, oriThirdType, user, methodService.getCurrentMaxVersion(oriMehtod.getInitMethodId()) + 1);
        Method newMethod = copyToMyMethod(saveDto);
        return newMethod.getId();
    }

    //从主执行人复制方法
    public Long copyMethodFromMainExecutor(Long otherMethodId, UserInfoVo user) {
        Method otherMethod = methodService.getById(otherMethodId);
        List<MethodPhase> otherPhaseList = methodPhaseService.listByMethodId(otherMethodId, null);
        List<MethodStep> otherStepList = methodStepService.listByMethodId(otherMethodId, null);
        List<MethodRelateReagent> otherRelateReagentList = methodRelateReagentService.listMethodRelateReagentByMethodId(otherMethodId);
        List<MethodRelateTimer> otherRelateTimerList = methodRelateTimerService.getByMethodId(otherMethodId);
        MethodType myThirdType = findMyThirdTypeOrCreateNew(user.getId(), otherMethod.getMethodTypeId(), true, true);
        List<Method> myMethodList = methodService.getSameTypeAndSameSourceMethod(otherMethod.getName(), myThirdType.getId(), otherMethod.getSourceMethodId(), user.getId());
        List<MethodPhase> myPhaseList = new ArrayList<>();
        List<MethodStep> myStepList = new ArrayList<>();
        Method myMethod = null;
        if (!CollectionUtils.isEmpty(myMethodList)) {
            myMethod = myMethodList.get(0);
        }
        if (myMethod != null) {
            myPhaseList = methodPhaseService.listByMethodId(myMethod.getId(), null);
            myStepList = methodStepService.listByMethodId(myMethod.getId(), null);
        }
        Users userShare = usersService.selectUser(otherMethod.getUserId(), null);
        MethodFullInfo existInfo = composeMethodFullInfo(myMethod, myPhaseList, myStepList, null, null);
        MethodFullInfo sourceInfo = composeMethodFullInfo(otherMethod, otherPhaseList, otherStepList, otherRelateReagentList, otherRelateTimerList);
        MethodSaveDto saveDto = new MethodSaveDto(existInfo, sourceInfo, MethodSourceEnum.SHARE, userShare.getName(), new Date(), myMethod == null, null, myThirdType, user, myMethod == null ? 0 : methodService.getCurrentMaxVersion(myMethod.getInitMethodId()) + 1);
        Method myNewMethod = copyToMyMethod(saveDto);
        return myNewMethod.getId();
    }

    public MethodFullInfo composeMethodFullInfo(Method
                                                        method, List<MethodPhase> phaseList, List<MethodStep> stepList, List<MethodRelateReagent> relateReagentList, List<MethodRelateTimer> relateTimerList) {
        MethodFullInfo info = new MethodFullInfo();
        info.setMethod(method);
        List<MethodPhaseWithStepList> phaseWithStepList = new ArrayList<>();
        info.setMethodPhaseWithStepListList(phaseWithStepList);
        if (!CollectionUtils.isEmpty(phaseList)) {
            phaseList.forEach(p -> {
                MethodPhaseWithStepList phase = new MethodPhaseWithStepList();
                phaseWithStepList.add(phase);
                phase.setPhase(p);
                if (!CollectionUtils.isEmpty(stepList)) {
                    List<MethodStep> pStepList = stepList.stream().filter(s -> s.getMethodPhaseId().equals(p.getId())).collect(Collectors.toList());
                    List<MethodStepWithReagentTimerList> stepWithInfoList = new ArrayList<>();
                    phase.setStepWithReagentTimerList(stepWithInfoList);
                    pStepList.forEach(ps -> {
                        MethodStepWithReagentTimerList stepWithInfo = new MethodStepWithReagentTimerList();
                        stepWithInfoList.add(stepWithInfo);
                        stepWithInfo.setStep(ps);
                        if (!CollectionUtils.isEmpty(relateReagentList)) {
                            List<MethodRelateReagent> reagentList = relateReagentList.stream().filter(r -> r.getStepId().equals(ps.getId())).collect(Collectors.toList());
                            stepWithInfo.setRelateReagentList(reagentList);
                        }
                        if (!CollectionUtils.isEmpty(relateTimerList)) {
                            List<MethodRelateTimer> timerList = relateTimerList.stream().filter(t -> t.getStepId().equals(ps.getId())).collect(Collectors.toList());
                            stepWithInfo.setRelateTimerList(timerList);
                        }
                    });
                }
            });
        }
        return info;
    }

    public Method copyToMyMethod(MethodSaveDto dto) {
        Method method = new Method();
        BeanUtils.copyProperties(dto.getSourceMethod().getMethod(), method);
        method.setCreateTime(null);
        method.setUpdateTime(null);
        setMethodInfo(method, dto);
        if (dto.getSourceEnum().equals(MethodSourceEnum.SHARE) || dto.getSourceEnum().equals(MethodSourceEnum.RECOMMEND)) {
            method.setFromTime(dto.getFromTime());
            method.setImportTime(new Date());
        }
        if (dto.getIsNewMethod() || MethodSourceEnum.CREATE.equals(dto.getSourceEnum())) {
            method.setCurrent(BoolEnum.TRUE.getValue());
            methodService.saveMethodAndUpdateInitId(method);
        } else {
            if (dto.getMyExistMethod() == null) {
                throw new BrillilabException(ResultEnum.REQUEST_PARAM_LACK);
            }
            method.setInitMethodId(dto.getMyExistMethod().getMethod().getInitMethodId());
            method.setSourceMethodId(dto.getMyExistMethod().getMethod().getSourceMethodId());
            if (MethodSourceEnum.REST_CURRENT.equals(dto.getSourceEnum())) {
                method.setRecommendMethodId(null);
                method.setFromType(dto.getSourceMethod().getMethod().getFromType());
                method.setCurrent(BoolEnum.TRUE.getValue());
                methodService.resetToCurrent(dto.getUser().getId(),dto.getSourceMethod().getMethod().getInitMethodId());
            }
            methodService.save(method);
        }
        if (!CollectionUtils.isEmpty(dto.getSourceMethod().getMethodPhaseWithStepListList())) {
            dto.getSourceMethod().getMethodPhaseWithStepListList().forEach(sourcePhase -> {
                savePhaseList(dto, sourcePhase, method.getId());
            });
        }
        if (dto.getMyExistMethod() != null && dto.getMyExistMethod().getMethod() != null) {
            MethodLabView view = methodLabViewService.getByInitMethodId(dto.getMyExistMethod().getMethod().getInitMethodId());
            MethodLabView newView = new MethodLabView();
            newView.setId(view.getId());
            newView.setCurrentMethodId(method.getId());
            methodLabViewService.updateById(newView);
        } else {
            MethodLabView newView = new MethodLabView();
            newView.setUserId(dto.getUser().getId());
            newView.setThirdMethodTypeName(dto.getMySelectedMethodThirdType().getName());
            newView.setCurrentMethodId(method.getId());
            newView.setThirdMethodTypeId(dto.getMySelectedMethodThirdType().getId());
            newView.setLabMemberId(dto.getUser().getLabMemberId());
            newView.setLabId(dto.getUser().getLabId());
            newView.setInitMethodId(method.getInitMethodId());
            newView.setFirstMethodTypeId(dto.getMySelectedMethodThirdType().getFirstId());
            methodLabViewService.save(newView);
        }
        return method;
    }

    public void setMethodInfo(Method method, MethodSaveDto dto) {
        method.setUpdateTime(null);
        method.setCreateTime(null);
        if (dto.getMySelectedMethodThirdType() == null) {
            throw new BrillilabException(ResultEnum.REQUEST_PARAM_LACK);
        }
        method.setMethodTypeId(dto.getMySelectedMethodThirdType().getId());
        method.setVersion(dto.getVersionCode());
        method.setSuccessCount(0);
        method.setExportCount(0);
        method.setUserId(dto.getUser().getId());
        method.setIsDelete(BoolEnum.FALSE.getValue());
        if (!StringUtils.isEmpty(dto.getNewName())) {
            method.setName(dto.getNewName());
        }
        method.setFromType(dto.getSourceEnum().getSourceType());
        method.setFromTime(dto.getFromTime());
        method.setSourceName(dto.getFromName());
        if (!MethodSourceEnum.CREATE.equals(dto.getSourceEnum())) {
            method.setSourceMethodId(dto.getSourceMethod().getMethod().getSourceMethodId());
        }
    }

    public void savePhaseList(MethodSaveDto dto, MethodPhaseWithStepList sourcePhase, Long methodId) {
        MethodPhase myPhase = new MethodPhase();
        BeanUtils.copyProperties(sourcePhase.getPhase(), myPhase);
        //myPhase.setIsDelete(BoolEnum.FALSE.getValue());
        myPhase.setMethodId(methodId);
        myPhase.setCreateTime(null);
        myPhase.setUpdateTime(null);
        if (dto.getIsNewMethod() || MethodSourceEnum.CREATE.equals(dto.getSourceEnum())) {
            methodPhaseService.savePhaseAndUpdateInitId(myPhase, dto.getSourceEnum().getSourceType());
        } else {
            if (dto.getMyExistMethod() != null && !CollectionUtils.isEmpty(dto.getMyExistMethod().getMethodPhaseWithStepListList())) {
                Optional<MethodPhaseWithStepList> optPhase = dto.getMyExistMethod().getMethodPhaseWithStepListList().stream().filter(dp -> dp.getPhase().getSourcePhaseId().equals(sourcePhase.getPhase().getSourcePhaseId())).findFirst();
                if (optPhase.isPresent()) {
                    myPhase.setInitPhaseId(optPhase.get().getPhase().getInitPhaseId());
                    methodPhaseService.save(myPhase);
                } else {
                    methodPhaseService.savePhaseAndUpdateInitId(myPhase, dto.getSourceEnum().getSourceType());
                }
            } else {
                methodPhaseService.savePhaseAndUpdateInitId(myPhase, dto.getSourceEnum().getSourceType());
            }
        }
        if (!CollectionUtils.isEmpty(sourcePhase.getStepWithReagentTimerList())) {
            sourcePhase.getStepWithReagentTimerList().forEach(stp -> {
                saveStepList(dto, stp, sourcePhase.getPhase().getSourcePhaseId(), methodId, myPhase.getId());
            });
        }
    }

    public void saveStepList(MethodSaveDto dto, MethodStepWithReagentTimerList sourceStep, Long sourcePhaseId, Long methodId, Long phaseId) {
        MethodStep myStep = new MethodStep();
        BeanUtils.copyProperties(sourceStep.getStep(), myStep);
        myStep.setMethodPhaseId(phaseId);
        //myStep.setIsDelete(BoolEnum.FALSE.getValue());
        myStep.setMethodId(methodId);
        myStep.setCreateTime(null);
        myStep.setUpdateTime(null);
        if (dto.getIsNewMethod() || MethodSourceEnum.CREATE.equals(dto.getSourceEnum())) {
            methodStepService.saveStepAndUpdateInitId(myStep, dto.getSourceEnum().getSourceType());
        } else {
            if (dto.getMyExistMethod() != null && !CollectionUtils.isEmpty(dto.getMyExistMethod().getMethodPhaseWithStepListList())) {
                Optional<MethodPhaseWithStepList> optExistPhase = dto.getMyExistMethod().getMethodPhaseWithStepListList().stream().filter(sp -> sp.getPhase().getSourcePhaseId().equals(sourcePhaseId)).findFirst();
                if (optExistPhase.isPresent()) {
                    if (!CollectionUtils.isEmpty(optExistPhase.get().getStepWithReagentTimerList())) {
                        Optional<MethodStepWithReagentTimerList> optExistStep = optExistPhase.get().getStepWithReagentTimerList().stream().filter(ds -> ds.getStep().getSourceStepId().equals(sourceStep.getStep().getSourceStepId())).findFirst();
                        if (optExistStep.isPresent()) {
                            myStep.setInitStepId(optExistStep.get().getStep().getInitStepId());
                            methodStepService.save(myStep);
                        } else {
                            methodStepService.saveStepAndUpdateInitId(myStep, dto.getSourceEnum().getSourceType());
                        }
                    } else {
                        methodStepService.saveStepAndUpdateInitId(myStep, dto.getSourceEnum().getSourceType());
                    }
                } else {
                    methodStepService.saveStepAndUpdateInitId(myStep, dto.getSourceEnum().getSourceType());
                }
            } else {
                methodStepService.saveStepAndUpdateInitId(myStep, dto.getSourceEnum().getSourceType());
            }
        }
        if (!CollectionUtils.isEmpty(sourceStep.getRelateReagentList())) {
            List<MethodRelateReagent> relateReagentVoList = sourceStep.getRelateReagentList().stream().filter(o -> o.getStepId().equals(sourceStep.getStep().getId())).collect(Collectors.toList());
            saveMethodRelateReagentList(methodId, phaseId, myStep.getId(), relateReagentVoList);
        }
        if (!CollectionUtils.isEmpty(sourceStep.getRelateTimerList())) {
            List<MethodRelateTimer> relateTimerList = sourceStep.getRelateTimerList().stream().filter(o -> o.getStepId().equals(sourceStep.getStep().getId())).collect(Collectors.toList());
            saveMethodRelateTimerList(methodId, phaseId, myStep.getId(), relateTimerList);
        }
    }

    public void saveMethodRelateReagentList(Long methodId, Long phaseId, Long
            stepId, List<MethodRelateReagent> relateReagentVoList) {
        if (!CollectionUtils.isEmpty(relateReagentVoList)) {
            List<MethodRelateReagent> relateReagentList = new ArrayList<>();
            relateReagentVoList.forEach(r -> {
                MethodRelateReagent reagent = new MethodRelateReagent();
                BeanUtils.copyProperties(r, reagent);
                reagent.setMethodId(methodId);
                reagent.setPhaseId(phaseId);
                reagent.setStepId(stepId);
                relateReagentList.add(reagent);
            });
            methodRelateReagentService.saveRelateReagentList(relateReagentList);
        }
    }

    public void saveMethodRelateTimerList(Long methodId, Long phaseId, Long
            stepId, List<MethodRelateTimer> relateTimerList) {
        if (!CollectionUtils.isEmpty(relateTimerList)) {
            List<MethodRelateTimer> saveRelateTimerList = new ArrayList<>();
            relateTimerList.forEach(r -> {
                MethodRelateTimer timer = new MethodRelateTimer();
                BeanUtils.copyProperties(r, timer);
                timer.setMethodId(methodId);
                timer.setPhaseId(phaseId);
                timer.setStepId(stepId);
                saveRelateTimerList.add(timer);
            });
            methodRelateTimerService.saveList(saveRelateTimerList);
        }
    }

    public boolean restoreMethod(Long methodId, Long userId) {
        Method method = methodService.getById(methodId);
        Assert.notNull(method,ResultEnum.DATA_NOT_EXIST.getMessage());
        if(!userId.equals(method.getUserId())){
            throw new BrillilabException(ResultEnum.DATA_NOT_EXIST);
        }
        Method newMethod = new Method();
        newMethod.setId(method.getId());
        newMethod.setIsDelete(BoolEnum.FALSE.getValue());
        return methodService.updateById(newMethod);
    }

    public Method importMethod(Long methodId, Long globalKitId, UserInfoVo user) {
        Method method = methodService.getById(methodId);
        Assert.notNull(method,ResultEnum.DATA_NOT_EXIST.getMessage());
        // 导入方法
        List<Method> exists = methodService.getByThirdTypeIdAndMethodNameAndUserId(method.getMethodTypeId(), method.getName(), user.getId());
        Long newMethodId;
        Long newMethodTypeId;
        if (CollectionUtils.isEmpty(exists)){
            newMethodId = methodRecommendLogic.dealToMyNewMethod(
                    user, method, MethodSourceEnum.IMPORT, method.getName(),
                    new Date(), method.getName(), null);
            Method newMethod = methodService.getById(newMethodId);
            Assert.notNull(newMethod,"操作失败!");
            newMethodTypeId = newMethod.getMethodTypeId();
        }else {
            Method current = exists.stream()
                    .filter(e -> BoolEnum.TRUE.getValue().equals(e.getCurrent())
                                    && BoolEnum.FALSE.getValue().equals(e.getIsDelete()))
                    .findFirst().orElse(null);
            Assert.notNull(current,"操作失败!");
            newMethodId = current.getId();
            newMethodTypeId = newMethodId;
        }

        // 导入试剂
        GlobalKit globalKit = globalKitService.selectById(globalKitId);
        if (globalKit!=null){
            Assert.isTrue(globalKit.getRelateMethodId().equals(methodId), "全局试剂未与该参考方法关联!");
            // 已经导入无需再次导入
            List<Kit> kits = kitService.selectListByFromId(user.getLabId(), globalKit.getId());
            // 更新relateMethodId
            if (CollectionUtils.isEmpty(kits)){
                Long newKitId = globalKitLogic.reagentImport(user.getLabId(), globalKit.getId(), user.getLabMemberId());
                Kit newKit = kitService.selectById(newKitId);
                if (newKit!=null){
                    newKit.setRelateMethodId(newMethodId);
                    newKit.setRelateMethodTypeId(newMethodTypeId);
                    newKit.setUpdateTime(null);
                    kitService.updateById(newKit);
                }
            }
        }

        return methodService.getById(newMethodId);
    }
}